package com.niiwoo.civet.trade.service.local.plan;

import com.niiwoo.civet.base.enums.FeeTypeEnum;
import com.niiwoo.civet.trade.constant.AmountHandleConstant;
import com.niiwoo.civet.trade.constant.DatePatternConstant;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dao.mapper.ProjectBorrowerPlanDetailMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectBorrowerPlanNewMapper;
import com.niiwoo.civet.trade.dao.mapper.ProjectBorrowerSummaryMapper;
import com.niiwoo.civet.trade.dao.mapper.ProjectInvestorPlanMapper;
import com.niiwoo.civet.trade.dto.BorrowerRepaymentDTO;
import com.niiwoo.civet.trade.dto.RateConfigDTO;
import com.niiwoo.civet.trade.dto.common.BuildRepaymentDTO;
import com.niiwoo.civet.trade.dto.request.loan.RepaymentPlanDTO;
import com.niiwoo.civet.trade.enums.InvestorPlanReceivedStatusEnum;
import com.niiwoo.civet.trade.enums.PeriodUnitEnum;
import com.niiwoo.civet.trade.enums.ProjectInvestOrderStatusEnum;
import com.niiwoo.civet.trade.enums.RepaymentTypeEnum;
import com.niiwoo.civet.trade.service.local.intelligenceInvest.ProjectPackageLocalService;
import com.niiwoo.tripod.consumer.helper.Exceptions;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.*;

/**
 * 按日计算利息
 *
 * @author liaojunjun
 *
 */
@Service
public class CalculateInterestByDay extends AbstractBorrowerInvestorRepaymentManager {

	private static final int CURRENT_PERIOD = 1;

	private static final int TOTAL_PERIOD = CURRENT_PERIOD;

	@Autowired
	private SnowflakeIdWorker snowflakeIdWorker;

	@Autowired
	private ProjectBorrowerSummaryMapper projectBorrowerSummaryMapper;

	@Autowired
	private ProjectBorrowerPlanNewMapper projectBorrowerPlanNewMapper;

	@Autowired
	private ProjectBorrowerPlanDetailMapperExt projectBorrowerPlanDetailMapperExt;

	@Autowired
	private ProjectInvestorPlanMapper projectInvestorPlanMapper;

	@Autowired
	private ProjectPackageLocalService projectPackageLocalService;

	@Override
	public boolean supports(InterestAccrualEnum interestAccrualEnum) {
		return InterestAccrualEnum.CALCULATE_INTEREST_BY_DAY.equals(interestAccrualEnum);
	}

	@Override
	public List<RepaymentPlanDTO> getBorrowerRepaymentPlan(BigDecimal amount, BigDecimal yearRate, Integer deadline,
			PeriodUnitEnum periodUnitEnum, Date startDate, Integer leastCalculateInterestDays) {
		if (!PeriodUnitEnum.DAY.equals(periodUnitEnum)) {
			new UnsupportedOperationException("按日计算利息 期限单位不是天");
		}

		List<RepaymentPlanDTO> result = new ArrayList<RepaymentPlanDTO>();
		Date refundDate = DateUtils.addDays(startDate, deadline - 1);
		BigDecimal dayRate = yearRate.divide(BigDecimal.valueOf(AmountHandleConstant.YEAR_OF_DAY), MathContext.DECIMAL128);

		RepaymentPlanDTO repaymentPlanDTO = new RepaymentPlanDTO();
		repaymentPlanDTO.setPlanType(RepaymentTypeEnum.REPAY_PRINCIPAL_INTEREST_AT_TERM.getValue());
		repaymentPlanDTO.setCurrentPeriod(TOTAL_PERIOD);
		repaymentPlanDTO.setTotalPeriod(TOTAL_PERIOD);
		// 如果借款期限小于最小计息天数 则使用最小计息天数计算利息
		// deadline.compareTo(leastCalculateInterestDays) < 0 ? leastCalculateInterestDays : deadline
		repaymentPlanDTO.setInterest(amount.multiply(dayRate)
				.multiply(BigDecimal.valueOf(deadline.compareTo(leastCalculateInterestDays) < 0 ? leastCalculateInterestDays : deadline)).setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO,
				BigDecimal.ROUND_HALF_EVEN));
		repaymentPlanDTO.setRefundDate(refundDate);
		repaymentPlanDTO.setPrincipal(amount);
		repaymentPlanDTO.setPrincipalInterest(repaymentPlanDTO.getPrincipal().add(repaymentPlanDTO.getInterest()));

		result.add(repaymentPlanDTO);

		return result;
	}

	@Override
	public List<RepaymentPlanDTO> getBorrowerRepaymentPlan(BuildRepaymentDTO buildRepaymentDTO, List<RateConfigDTO> rateConfigDTOList) {
		PeriodUnitEnum periodUnit = buildRepaymentDTO.getPeriodUnit();
		if (!PeriodUnitEnum.DAY.equals(periodUnit)) {
			new UnsupportedOperationException("按日计算利息 期限单位不是天");
		}
		// 担保服务费
		BigDecimal guaranteeServiceFeeTotal = buildRepaymentDTO.getAmount().multiply(buildRepaymentDTO.getGuaranteeRate())
				.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);

		// 平台管理费
		BigDecimal platformManageFeeTotal = buildRepaymentDTO.getAmount().multiply(buildRepaymentDTO.getManageRate())
				.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);

		List<RepaymentPlanDTO> result = new ArrayList<RepaymentPlanDTO>();

		Date refundDate = DateUtils.addDays(buildRepaymentDTO.getStartDate() == null ? new Date() : buildRepaymentDTO.getStartDate(), buildRepaymentDTO.getDeadline() - 1);
		BigDecimal dayRate = buildRepaymentDTO.getYearRate().divide(BigDecimal.valueOf(AmountHandleConstant.YEAR_OF_DAY), MathContext.DECIMAL128);

		RepaymentPlanDTO repaymentPlanDTO = new RepaymentPlanDTO();
		repaymentPlanDTO.setPlanType(RepaymentTypeEnum.REPAY_PRINCIPAL_INTEREST_AT_TERM.getValue());
		repaymentPlanDTO.setCurrentPeriod(TOTAL_PERIOD);
		repaymentPlanDTO.setTotalPeriod(TOTAL_PERIOD);
		// 如果借款期限小于最小计息天数 则使用最小计息天数计算利息
		// buildRepaymentDTO.getDeadline().compareTo(buildRepaymentDTO.getLeastCalculateInterestDays()) < 0 ? buildRepaymentDTO.getLeastCalculateInterestDays() : buildRepaymentDTO.getDeadline()
		repaymentPlanDTO.setInterest(buildRepaymentDTO.getAmount().multiply(dayRate)
				.multiply(BigDecimal.valueOf(buildRepaymentDTO.getDeadline().compareTo(buildRepaymentDTO.getLeastCalculateInterestDays()) < 0 ? buildRepaymentDTO.getLeastCalculateInterestDays() : buildRepaymentDTO.getDeadline())).setScale(
				AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN));
		repaymentPlanDTO.setRefundDate(refundDate);
		repaymentPlanDTO.setPrincipal(buildRepaymentDTO.getAmount());
		repaymentPlanDTO.setPrincipalInterest(repaymentPlanDTO.getPrincipal().add(repaymentPlanDTO.getInterest()));

		repaymentPlanDTO.setGuaranteeServiceFee(guaranteeServiceFeeTotal);
		repaymentPlanDTO.setPlatformManageFee(platformManageFeeTotal);

		repaymentPlanDTO.setRepaymentTotalAmount(repaymentPlanDTO.getPrincipalInterest()
				.add(repaymentPlanDTO.getGuaranteeServiceFee()).add(repaymentPlanDTO.getPlatformManageFee()));

		result.add(repaymentPlanDTO);
		return result;
	}

	@Override
	public BorrowerRepaymentDTO buildBorrowerRepaymentPlan(Project project,
			ProjectBorrowerSummary projectBorrowerSummary, List<ProjectRate> rateConfigDTOList) {
		PeriodUnitEnum periodUnit = PeriodUnitEnum.enumOf(project.getDeadlineUnit());
		if (PeriodUnitEnum.DAY != periodUnit) {
			Exceptions.throwBizException("TRD_700003");// 等额本息还款方式的期限单位不是月
		}
		BorrowerRepaymentDTO result = new BorrowerRepaymentDTO();
		Date refundDate = DateUtils.addDays(project.getFullSuccessTime(), project.getDeadline() - 1);
		BigDecimal dayRate = project.getBorrowRate().divide(BigDecimal.valueOf(AmountHandleConstant.YEAR_OF_DAY), MathContext.DECIMAL128);

		projectBorrowerSummary.setTotalPeriod(TOTAL_PERIOD);
		projectBorrowerSummary.setRefundDate(refundDate);
		projectBorrowerSummary.setAutoRefundDate(projectBorrowerSummary.getRefundDate());

		projectBorrowerSummaryMapper.insertSelective(projectBorrowerSummary);

		ProjectBorrowerPlanNew projectBorrowerPlanNew = buildProjectBorrowerPlanNew(snowflakeIdWorker.nextId(),
				project.getProjectId(), project.getBorrowUserId(), project.getBorrowAccountId(), refundDate, CURRENT_PERIOD, periodUnit.getValue(), TOTAL_PERIOD);
		projectBorrowerPlanNewMapper.insertSelective(projectBorrowerPlanNew);


		// 担保服务费
		BigDecimal guaranteeServiceFeeTotal = project.getContractAmount().multiply(project.getGuaranteeRate())
				.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
		ProjectBorrowerPlanDetail guaranteeServiceFee = buildProjectBorrowerPlanDetail(snowflakeIdWorker.nextId(),
				project.getProjectId(), project.getBorrowUserId(), projectBorrowerPlanNew.getId(), FeeTypeEnum.GUARANTEE_FEE.getValue().intValue(), guaranteeServiceFeeTotal);
		projectBorrowerPlanDetailMapperExt.insertSelective(guaranteeServiceFee);

		// 平台管理费
		BigDecimal platformManageFeeTotal = project.getContractAmount().multiply(project.getManageRate())
				.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
		ProjectBorrowerPlanDetail platformManageFee = buildProjectBorrowerPlanDetail(snowflakeIdWorker.nextId(),
				project.getProjectId(), project.getBorrowUserId(), projectBorrowerPlanNew.getId(), FeeTypeEnum.MANAGEMENT_FEE.getValue().intValue(), platformManageFeeTotal);
		projectBorrowerPlanDetailMapperExt.insertSelective(platformManageFee);

		// 本金
		ProjectBorrowerPlanDetail capital = buildProjectBorrowerPlanDetail(snowflakeIdWorker.nextId(), project.getProjectId(),
				project.getBorrowUserId(), projectBorrowerPlanNew.getId(), FeeTypeEnum.CAPITAL.getValue().intValue(), project.getContractAmount());
		projectBorrowerPlanDetailMapperExt.insertSelective(capital);

		// 利息
		BigDecimal interest = project.getContractAmount().multiply(dayRate)
				.multiply(BigDecimal.valueOf(project.getDeadline().compareTo(project.getLeastCalculateInterestDays()) < 0 ? project.getLeastCalculateInterestDays() : project.getDeadline()))
				.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
		ProjectBorrowerPlanDetail interestDetail = buildProjectBorrowerPlanDetail(snowflakeIdWorker.nextId(),
				project.getProjectId(), project.getBorrowUserId(), projectBorrowerPlanNew.getId(), FeeTypeEnum.INTEREST.getValue().intValue(), interest);
		projectBorrowerPlanDetailMapperExt.insertSelective(interestDetail);

		List<ProjectBorrowerPlanNew> projectBorrowerPlanNewList = new ArrayList<>();
		projectBorrowerPlanNewList.add(projectBorrowerPlanNew);

		result.setProjectBorrowerSummary(projectBorrowerSummary);
		result.setProjectBorrowerPlanNewList(projectBorrowerPlanNewList);
		return result;
	}

	@Override
	public List<ProjectInvestorPlan> buildInvestorRepaymentPlan(Project project,
			List<ProjectInvestOrder> projectInvestOrderList, BorrowerRepaymentDTO borrowerRepaymentDTO) {
		PeriodUnitEnum periodUnit = PeriodUnitEnum.enumOf(project.getDeadlineUnit());
		if (PeriodUnitEnum.DAY != periodUnit) {
			Exceptions.throwBizException("TRD_700003");// 等额本息还款方式的期限单位不是月
		}
		List<ProjectInvestorPlan> result = new ArrayList<ProjectInvestorPlan>();
		BigDecimal dayRate = project.getBorrowRate().divide(BigDecimal.valueOf(AmountHandleConstant.YEAR_OF_DAY), MathContext.DECIMAL128);

		Map<Integer, BigDecimal> investCapitalTotal = new HashMap<>();
		Map<Integer, BigDecimal> investInterestTotal = new HashMap<>();

		List<ProjectBorrowerPlanNew> projectBorrowerPlanNewList = borrowerRepaymentDTO.getProjectBorrowerPlanNewList();

		boolean isPackagedProject = projectPackageLocalService.isPackagedProject(project.getProjectId());

		for (ProjectInvestOrder projectInvestOrder : projectInvestOrderList) {
			if (projectInvestOrder != null
					&& ProjectInvestOrderStatusEnum.SUCCESS.getValue().equals(projectInvestOrder.getStatus())) {
				for (ProjectBorrowerPlanNew projectBorrowerPlanNew : projectBorrowerPlanNewList) {
					ProjectInvestorPlan projectInvestorPlan = new ProjectInvestorPlan();
					projectInvestorPlan.setId(snowflakeIdWorker.nextId());
					projectInvestorPlan.setInvestOrderId(projectInvestOrder.getId());
					projectInvestorPlan.setInvestType(isPackagedProject ? Byte.valueOf("3") : Byte.valueOf("1"));
					projectInvestorPlan.setProjectId(projectInvestOrder.getProjectId());
                    projectInvestorPlan.setOrgId(project.getOrgId());
					projectInvestorPlan.setUserId(projectInvestOrder.getUserId());
                    projectInvestorPlan.setAccountId(projectInvestOrder.getAccountId());
                    projectInvestorPlan.setPlatformUserNo(projectInvestOrder.getPlatformUserNo());
					projectInvestorPlan.setCurrentPeriod(projectBorrowerPlanNew.getPeriod());
					projectInvestorPlan.setTotalPeriod(projectBorrowerPlanNew.getTotalPeriod());
					projectInvestorPlan.setReceivedDate(projectBorrowerPlanNew.getRefundDate());
					projectInvestorPlan.setYearMouth(DateFormatUtils.format(projectBorrowerPlanNew.getRefundDate(),
							DatePatternConstant.YYYYMM));
					projectInvestorPlan.setPenaltyBeginDate(projectBorrowerPlanNew.getRefundDate());
					projectInvestorPlan.setReceivedInterest(BigDecimal.ZERO);
					projectInvestorPlan.setReceivedCapital(BigDecimal.ZERO);
					projectInvestorPlan.setReceivedPenaltyFee(BigDecimal.ZERO);
					projectInvestorPlan.setCapital(projectInvestOrder.getAmount());

					projectInvestorPlan.setInterest(projectInvestOrder.getAmount().multiply(dayRate)
							.multiply(BigDecimal.valueOf(project.getDeadline().compareTo(project.getLeastCalculateInterestDays()) < 0 ? project.getLeastCalculateInterestDays() : project.getDeadline()))
							.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN));

					projectInvestorPlan.setReceivedStatus(InvestorPlanReceivedStatusEnum.NON_RECEIVE.getCode());
					projectInvestorPlan.setInvestTime(projectInvestOrder.getCreateTime());
					projectInvestorPlan.setCreateTime(new Date());
					projectInvestorPlan.setUpdateTime(new Date());

					projectInvestorPlanMapper.insertSelective(projectInvestorPlan);

					result.add(projectInvestorPlan);

					if (investCapitalTotal.get(projectBorrowerPlanNew.getPeriod()) == null) {
						investCapitalTotal.put(projectBorrowerPlanNew.getPeriod(), projectInvestorPlan.getCapital());
						investInterestTotal.put(projectBorrowerPlanNew.getPeriod(), projectInvestorPlan.getInterest());
					} else {
						investCapitalTotal.put(projectBorrowerPlanNew.getPeriod(), investCapitalTotal.get(projectBorrowerPlanNew.getPeriod()).add(projectInvestorPlan.getCapital()));
						investInterestTotal.put(projectBorrowerPlanNew.getPeriod(), investInterestTotal.get(projectBorrowerPlanNew.getPeriod()).add(projectInvestorPlan.getInterest()));
					}
				}
			}
		}

		/**
		 * 更新借款人应还款本金为投资人应收款本金之和,应还款利息为投资人应收款利息之和
		 */
		updateBorrowerCapitalInterest(projectBorrowerPlanDetailMapperExt, investCapitalTotal, investInterestTotal, projectBorrowerPlanNewList);
		return result;
	}
}
